home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
PC World Komputer 2007 December
/
PCWKCD1207B.iso
/
Blogowanie poza sfera
/
Flock 0.9.1.3 stable
/
flock-0.9.1.3.en-US.win32.exe
/
flock
/
components
/
flockMetricsService.js
< prev
next >
Wrap
Text File
|
2007-10-12
|
18KB
|
645 lines
//
// BEGIN FLOCK GPL
//
// Copyright Flock Inc. 2005-2007
// http://flock.com
//
// This file may be used under the terms of of the
// GNU General Public License Version 2 or later (the "GPL"),
// http://www.gnu.org/licenses/gpl.html
//
// Software distributed under the License is distributed on an "AS IS" basis,
// WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
// for the specific language governing rights and limitations under the
// License.
//
// END FLOCK GPL
//
const MS_CONTRACTID = '@flock.com/metrics-service;1';
const MS_CLASSID = Components.ID('{bc1358fa-6e36-4d0d-a401-b0b02111114c}');
const MS_CLASSNAME = 'Flock Metrics Service';
const ENABLED_BY_DEFAULT = true;
const LOGGING_URL = 'http://metrics.flock.com/collect.php';
const PREF_FLOCK_METRICS_ENABLED = 'flock.metrics.enabled';
const PREF_FLOCK_METRICS_SHUTDOWN = 'flock.metrics.shutdownClean';
const PREF_FLOCK_METRICS_INTERVAL = 'flock.metrics.interval';
const DEFAULT_METRICS_INTERVAL = 86400;
const PREF_FLOCK_FIRST_RUN_DATE = 'flock.first_run.bigDate';
const PREF_USERAGENT_EDITION = 'general.useragent.edition';
const PREF_DEFAULT_SEARCH_ENGINE = 'browser.search.selectedEngine';
const PREF_DEFAULT_ENGINE_NAME = 'browser.search.defaultenginename';
const PREF_MYWORLD_SEARCH_ENGINE = 'flock.myworld.currentEngine';
const PREF_START_PAGE = 'browser.startup.homepage';
const PREF_FEED_SELECTED_ACTION = 'browser.feeds.handler';
const URI_BRAND_PROPERTIES = 'chrome://branding/locale/brand.properties';
const MYWORLD_URL = 'about:myworld';
const Cc = Components.classes;
const Ci = Components.interfaces;
const Cr = Components.results;
/* from nspr's prio.h */
const PR_RDONLY = 0x01;
const PR_WRONLY = 0x02;
const PR_RDWR = 0x04;
const PR_CREATE_FILE = 0x08;
const PR_APPEND = 0x10;
const PR_TRUNCATE = 0x20;
const PR_SYNC = 0x40;
const PR_EXCL = 0x80;
var gApp = null;
function getObserverService() {
return Cc['@mozilla.org/observer-service;1']
.getService(Ci.nsIObserverService);
}
function getCharPref(prefName, defaultValue) {
try {
var prefs = Cc['@mozilla.org/preferences-service;1']
.getService(Ci.nsIPrefBranch);
return prefs.getCharPref(prefName);
}
catch (e) {
return defaultValue;
}
}
function getIntPref(prefName, defaultValue) {
try {
var prefs = Cc['@mozilla.org/preferences-service;1']
.getService(Ci.nsIPrefBranch);
return prefs.getIntPref(prefName);
}
catch (e) {
return defaultValue;
}
}
function getBoolPref(prefName, defaultValue) {
try {
var prefs = Cc['@mozilla.org/preferences-service;1']
.getService(Ci.nsIPrefBranch);
return prefs.getBoolPref(prefName);
}
catch (e) {
return defaultValue;
}
}
function MetricsService() {
gApp = Cc['@mozilla.org/xre/app-info;1']
.getService(Ci.nsIXULAppInfo)
.QueryInterface(Ci.nsIXULRuntime);
this._createStore();
var obs = getObserverService();
obs.addObserver(this, 'flock-data-ready', false);
obs.addObserver(this, 'quit-application', false);
obs.addObserver(this, 'xpcom-shutdown', false);
this._enabled = ENABLED_BY_DEFAULT;
if (this._enabled)
this.observe(null, 'nsPref:changed', null);
}
MetricsService.prototype = {
_start: function MS__start() {
this._logger = Cc['@flock.com/logger;1'].createInstance(Ci.flockILogger);
this._logger.init('metrics');
this._logger.info('starting up...');
this._saveTimer = null;
this._coop = Cc['@flock.com/singleton;1'].getService(Ci.flockISingleton)
.getSingleton('chrome://browser/content/flock/common/load-faves-coop.js')
.wrappedJSObject;
var prefs = Cc['@mozilla.org/preferences-service;1']
.getService(Ci.nsIPrefBranch2);
prefs.addObserver(PREF_FLOCK_METRICS_ENABLED, this, false);
this.observe(null, 'nsPref:changed', null);
this._watchAuthEvents();
if (prefs.prefHasUserValue(PREF_FLOCK_METRICS_SHUTDOWN) &&
prefs.getBoolPref(PREF_FLOCK_METRICS_SHUTDOWN) == false)
this.reportCount('crash');
prefs.setBoolPref(PREF_FLOCK_METRICS_SHUTDOWN, false);
prefs.QueryInterface(Ci.nsIPrefService);
prefs.savePrefFile(null);
this.reportCount('start');
var tm = Cc['@mozilla.org/updates/timer-manager;1']
.getService(Ci.nsIUpdateTimerManager);
var interval = getIntPref(PREF_FLOCK_METRICS_INTERVAL,
DEFAULT_METRICS_INTERVAL);
tm.registerTimer('background-metrics-timer', this, interval);
},
_stop: function MS__stop() {
if (this._saveTimer) {
this._saveTimer.cancel();
this._saveTimer = null;
}
this._saveStore();
var prefs = Cc['@mozilla.org/preferences-service;1']
.getService(Ci.nsIPrefBranch);
prefs.setBoolPref(PREF_FLOCK_METRICS_SHUTDOWN, true);
},
_shutdown: function MS__shutdown() {
gApp = null;
},
_configure: function MS__configure() {
this._enabled = getBoolPref(PREF_FLOCK_METRICS_ENABLED, ENABLED_BY_DEFAULT);
if (!this._enabled) {
var file = this._getMetricsFile();
try {
file.remove(false);
}
catch (e) { }
}
},
_prefChanged: function MS__prefChanged(state) {
this._configure();
},
observe: function MS_observe(subject, topic, state) {
var obs = getObserverService();
switch (topic) {
case 'flock-data-ready':
obs.removeObserver(this, 'flock-data-ready');
this._start();
break;
case 'quit-application':
obs.removeObserver(this, 'quit-application');
this._stop();
break;
case 'xpcom-shutdown':
obs.removeObserver(this, 'xpcom-shutdown');
this._shutdown();
break;
case 'nsPref:changed':
this._prefChanged(state);
break;
case 'timer-callback':
this._saveTimer = null;
this._saveStore();
break;
}
},
notify: function MS_notify(timer) {
this._sendReport();
},
_getMetricsFile: function MS__getMetricsFile() {
var file = Cc['@mozilla.org/file/directory_service;1']
.getService(Ci.nsIProperties).get('ProfD', Ci.nsILocalFile);
file.append('mstore.js');
return file;
},
_fillBaseInfo: function MS__fillBaseInfo(store) {
store['version'] = gApp.version;
store['buildID'] = gApp.appBuildID;
store['firstRun'] = getCharPref(PREF_FLOCK_FIRST_RUN_DATE, '0');
store['edition'] = getCharPref(PREF_USERAGENT_EDITION, '');
var sbs = Cc['@mozilla.org/intl/stringbundle;1']
.getService(Ci.nsIStringBundleService);
var bundle = sbs.createBundle(URI_BRAND_PROPERTIES);
store['product'] = bundle.GetStringFromName('brandShortName');
},
_fillPrefInfo: function MS__fillPrefInfo(store) {
var prefs = Cc['@mozilla.org/preferences-service;1']
.getService(Ci.nsIPrefBranch);
var defaultEngine;
try {
defaultEngine = prefs.getCharPref(PREF_DEFAULT_SEARCH_ENGINE);
}
catch (e) {
defaultEngine = prefs.getComplexValue(PREF_DEFAULT_ENGINE_NAME,
Ci.nsIPrefLocalizedString).data;
}
if (!defaultEngine)
defaultEngine = '';
store['default search engine'] = defaultEngine;
var startPageHasMyWorld = false;
try {
var startPage = prefs.getComplexValue(PREF_START_PAGE,
Ci.nsIPrefLocalizedString).data;
var startPages = startPage.split('|');
for each (var url in startPages) {
// Trim leading/trailing whitespace from URL
url = url.replace(/(^\s+)|(\s+$)/g, "");
if (url == MYWORLD_URL) {
startPageHasMyWorld = true;
break;
}
}
}
catch (e) { }
store['myworld start page'] = startPageHasMyWorld;
store['myworld search engine'] =
getCharPref(PREF_MYWORLD_SEARCH_ENGINE, '');
var action = getCharPref(PREF_FEED_SELECTED_ACTION);
var feedReader;
if (action == 'ask')
feedReader = 'news';
else if (action == 'bookmarks')
feedReader = 'livemarks';
else
feedReader = 'other';
store['default feed reader'] = feedReader;
store['metrics enabled'] = this._enabled;
},
_initStore: function MS__initStore() {
this._store = {};
this._fillBaseInfo(this._store);
this._fillPrefInfo(this._store);
},
_createStore: function MS__createStore() {
var store;
try {
var file = this._getMetricsFile();
var stream = Cc['@mozilla.org/network/file-input-stream;1']
.createInstance(Ci.nsIFileInputStream);
stream.init(file, PR_RDONLY, 0, 0);
var cvstream = Cc['@mozilla.org/intl/converter-input-stream;1']
.createInstance(Ci.nsIConverterInputStream);
cvstream.init(stream, 'UTF-8', 1024,
Ci.nsIConverterInputStream.DEFAULT_REPLACEMENT_CHARACTER);
var content = '';
var data = {};
while (cvstream.readString(4096, data)) {
content += data.value;
}
cvstream.close();
store = content.replace(/\r\n?/g, '\n');
}
catch (e) {
store = null;
}
if (store) {
try {
this._store = this._safeEval(store);
return;
}
catch (e) { }
}
this._initStore();
},
_saveStore: function MS__saveStore() {
if (!this._enabled) return;
try {
var file = this._getMetricsFile();
var ostream = Cc['@mozilla.org/network/safe-file-output-stream;1']
.createInstance(Ci.nsIFileOutputStream);
ostream.init(file, PR_WRONLY | PR_CREATE_FILE | PR_TRUNCATE, 0600, 0);
var converter = Cc['@mozilla.org/intl/scriptableunicodeconverter']
.createInstance(Ci.nsIScriptableUnicodeConverter);
converter.charset = 'UTF-8';
var data = this._store.toSource();
var convdata = converter.ConvertFromUnicode(data) + converter.Finish();
ostream.write(convdata, convdata.length);
if (ostream instanceof Ci.nsISafeOutputStream) {
ostream.finish();
} else {
ostream.close();
}
}
catch (e) { }
},
_scheduleSaveStore: function MS__scheduleSaveStore() {
if (!this._enabled) return;
if (!this._saveTimer) {
this._saveTimer = Cc['@mozilla.org/timer;1'].createInstance(Ci.nsITimer);
this._saveTimer.init(this, 5000, Ci.nsITimer.TYPE_ONE_SHOT);
}
},
_watchAuthEvents: function MS__watchAuthEvents() {
var RDFS = Cc['@mozilla.org/rdf/rdf-service;1']
.getService(Ci.nsIRDFService);
var isAuth = RDFS.GetResource("http://flock.com/rdf#isAuthenticated");
var faves = Cc['@mozilla.org/rdf/datasource;1?name=flock-favorites']
.getService(Ci.flockIRDFObservable);
faves.addArcObserver(Ci.flockIRDFObserver.WATCH_TYPES, null,
isAuth, RDFS.GetLiteral("true"), this);
},
rdfChanged: function MS_rdfChanged(ds, type, rsrc, pred, obj, oldObj) {
var acct = this._coop.get_from_resource(rsrc);
var svc = Cc[acct.serviceId].getService(Ci.flockIWebService);
this.reportCount('login ' + svc.shortName);
},
report: function MS_report(key, value) {
if (!this._enabled) return;
this._store[key] = value;
this._scheduleSaveStore();
},
reportNow: function MS_reportNow(key, value) {
if (this._enabled)
this._sendQuickReport(key, value);
},
reportCount: function MS_reportCount(key) {
if (!this._enabled) return;
if (this._store[key])
this._store[key]++;
else
this._store[key] = 1;
this._scheduleSaveStore();
},
_sendReport: function MS__sendReport() {
if (this._enabled) {
this._fillBaseInfo(this._store);
this._fillPrefInfo(this._store);
this._sendData(this._toJSONString(this._store));
} else {
this._sendQuickReport('metrics enabled', false);
}
this._initStore();
this._saveStore();
},
_sendQuickReport: function MS__sendQuickReport(key, value) {
var data = {};
data[key] = value;
this._fillBaseInfo(data);
this._sendData(this._toJSONString(data));
},
_sendData: function MS__sendData(data) {
if (gApp.appBuildID == '0000000000')
return;
try {
var hr = Cc['@mozilla.org/xmlextras/xmlhttprequest;1']
.createInstance(Ci.nsIXMLHttpRequest);
var self = this;
hr.onerror = function(evt) { self._onError(evt); };
hr.onload = function(evt) { self._onLoad(evt); };
hr.detachLoadGroup = true;
hr.open('POST', LOGGING_URL);
hr.send(data);
}
catch (e) {
this._onError(null);
}
},
_onError: function MS__onError(evt) {
},
_onLoad: function MS__onLoad(evt) {
},
/* The next two functions taken from nsSessionStore.js */
/**
* safe eval'ing
*/
_safeEval: function sss_safeEval(aStr) {
var s = new Components.utils.Sandbox("about:blank");
return Components.utils.evalInSandbox(aStr, s);
},
/**
* Converts a JavaScript object into a JSON string
* (see http://www.json.org/ for the full grammar).
*
* The inverse operation consists of eval("(" + JSON_string + ")");
* and should be provably safe.
*
* @param aJSObject is the object to be converted
* @return the object's JSON representation
*/
_toJSONString: function sss_toJSONString(aJSObject) {
// these characters have a special escape notation
const charMap = { "\b": "\\b", "\t": "\\t", "\n": "\\n", "\f": "\\f",
"\r": "\\r", '"': '\\"', "\\": "\\\\" };
// we use a single string builder for efficiency reasons
var parts = [];
// this recursive function walks through all objects and appends their
// JSON representation to the string builder
function jsonIfy(aObj) {
if (typeof aObj == "boolean") {
parts.push(aObj ? "true" : "false");
}
else if (typeof aObj == "number" && isFinite(aObj)) {
// there is no representation for infinite numbers or for NaN!
parts.push(aObj.toString());
}
else if (typeof aObj == "string") {
aObj = aObj.replace(/[\\"\x00-\x1F\u0080-\uFFFF]/g, function($0) {
// use the special escape notation if one exists, otherwise
// produce a general unicode escape sequence
return charMap[$0] ||
"\\u" + ("0000" + $0.charCodeAt(0).toString(16)).slice(-4);
});
parts.push('"' + aObj + '"')
}
else if (aObj == null) {
parts.push("null");
}
else if (aObj instanceof Array) {
parts.push("[");
for (var i = 0; i < aObj.length; i++) {
jsonIfy(aObj[i]);
parts.push(",");
}
if (parts[parts.length - 1] == ",")
parts.pop(); // drop the trailing colon
parts.push("]");
}
else if (typeof aObj == "object") {
parts.push("{");
for (var key in aObj) {
jsonIfy(key.toString());
parts.push(":");
jsonIfy(aObj[key]);
parts.push(",");
}
if (parts[parts.length - 1] == ",")
parts.pop(); // drop the trailing colon
parts.push("}");
}
else {
throw new Error("No JSON representation for this object!");
}
}
jsonIfy(aJSObject);
var newJSONString = parts.join(" ");
// sanity check - so that API consumers can just eval this string
if (/[^,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t]/.test(
newJSONString.replace(/"(\\.|[^"\\])*"/g, "")
))
throw new Error("JSON conversion failed unexpectedly!");
return newJSONString;
},
getInterfaces: function MS_getInterfaces(countRef) {
var interfaces = [Ci.flockIMetricsService, Ci.flockIRDFObserver,
Ci.nsITimerCallback, Ci.nsIObserver, Ci.nsIClassInfo,
Ci.nsISupports];
countRef.value = interfaces.length;
return interfaces;
},
getHelperForLanguage: function MS_getHelperForLanguage(language) {
return null;
},
contractID: MS_CONTRACTID,
classDescription: MS_CLASSNAME,
classID: MS_CLASSID,
implementationLanguage: Ci.nsIProgrammingLanguage.JAVASCRIPT,
flags: Ci.nsIClassInfo.SINGLETON,
QueryInterface: function MS_QueryInterface(iid) {
if (iid.equals(Ci.flockIMetricsService) ||
iid.equals(Ci.flockIRDFObserver) ||
iid.equals(Ci.nsITimerCallback) ||
iid.equals(Ci.nsIObserver) ||
iid.equals(Ci.nsIClassInfo) ||
iid.equals(Ci.nsISupports))
return this;
throw Cr.NS_ERROR_NO_INTERFACE;
}
}
function GenericComponentFactory(ctor) {
this._ctor = ctor;
}
GenericComponentFactory.prototype = {
_ctor: null,
// nsIFactory
createInstance: function(outer, iid) {
if (outer != null)
throw Cr.NS_ERROR_NO_AGGREGATION;
return (new this._ctor()).QueryInterface(iid);
},
// nsISupports
QueryInterface: function(iid) {
if (iid.equals(Ci.nsIFactory) ||
iid.equals(Ci.nsISupports))
return this;
throw Cr.NS_ERROR_NO_INTERFACE;
},
};
var Module = {
QueryInterface: function(iid) {
if (iid.equals(Ci.nsIModule) ||
iid.equals(Ci.nsISupports))
return this;
throw Cr.NS_ERROR_NO_INTERFACE;
},
getClassObject: function(cm, cid, iid) {
if (!iid.equals(Ci.nsIFactory))
throw Cr.NS_ERROR_NOT_IMPLEMENTED;
if (cid.equals(MS_CLASSID))
return new GenericComponentFactory(MetricsService)
throw Cr.NS_ERROR_NO_INTERFACE;
},
registerSelf: function(cm, file, location, type) {
var cr = cm.QueryInterface(Ci.nsIComponentRegistrar);
cr.registerFactoryLocation(MS_CLASSID, MS_CLASSNAME, MS_CONTRACTID,
file, location, type);
var catman = Cc['@mozilla.org/categorymanager;1']
.getService(Ci.nsICategoryManager);
catman.addCategoryEntry('flock-startup', MS_CLASSNAME,
'service,' + MS_CONTRACTID,
true, true);
},
unregisterSelf: function(cm, location, type) {
var cr = cm.QueryInterface(Ci.nsIComponentRegistrar);
cr.unregisterFactoryLocation(MS_CLASSID, location);
},
canUnload: function(cm) {
return true;
},
};
function NSGetModule(compMgr, fileSpec)
{
return Module;
}